package com.pclong.sql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.pclong.util.debug.Debug;

public class SQLHelper {

	private final int OPERATIONFAILEDSTATUS = -1;
	private final String IDFIELD = "id";
	
	/**
	 * 全局使用的SQLGenerator。
	 */
	private static SQLGenerator generator = DataSourceProvider.getSQLGenerator();
	private static Debug debug = DataSourceProvider.getDebug(SQLHelper.class);

	// ==================================================================================
	// INSERT_OPERATIONS
	// ==================================================================================
	/**
	 * 给定表名tableName、所有列名数组colNames及对应的参数队列params，新增一条记录。
	 */
	public Integer insertRecord(String tableName, String[] colNames, Object... values) {
		Integer insertedId = null;
		String insertSQL = generator.generateInsertStatement(tableName, colNames);
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		try {
			queryRunner.update(connection, insertSQL, values);
			insertedId = (Integer) queryRunner.query(connection, generator.getInsertedIdMethod(),
					new ScalarHandler(1));
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return insertedId;
	}
	
	/**
	 * 给定表名tableName、需要修改的列名数组colNames及对应的Bean，修改数据库中的相关记录（即与此Bean的ID相同的记录）。
	 */
	public Integer insertRecord(String tableName, String[] colNames, Object bean) {
		String insertSQL = generator.generateInsertStatement(tableName, colNames);
		
		return insertBean(insertSQL, bean, colNames);
	}
	
	// ==================================================================================
	// UPDATE_OPERATIONS
	// ==================================================================================
	/**
	 * 给定一条update更新语句updateSQL及参数队列params修改对应记录。
	 * 参数队列的顺序必须与updateSQL中的所有'?'号一一对应。
	 */
	public int updateRecords(String updateSQL, Object... params) {
		int status = OPERATIONFAILEDSTATUS;
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		try {
			status = queryRunner.update(connection, updateSQL, params);
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return status;
	}
	
	/**
	 * 给定一条update更新语句updateSQL修改对应记录（没有参数，修改参数已包含在更新语句中）。
	 */
	public int updateRecords(String updateSQL) {
		return updateRecords(updateSQL, (Object[]) null);
	}
	
	/**
	 * 给定表名tableName、需要修改的列名数组colNames、
	 * 查询条件where（where参数中需要自带where关键字）及参数队列params修改对应记录。
	 * 参数队列的顺序必须与colNames和where条件的所有'?'号一一对应。
	 */
	public int updateRecords(String tableName, String[] colNames, String where, Object... params) {
		String updateSQL = generator.generateUpdateStatementWhere(tableName, colNames, where);
		
		return updateRecords(updateSQL, params);
	}
	
	/**
	 * 给定表名tableName、需要修改的列名colName（只修改一列属性）、
	 * 查询条件where（where参数中需要自带where关键字）及参数队列params修改对应记录。
	 * 参数队列的顺序必须与colName和where条件的所有'?'号一一对应。
	 */
	public int updateRecords(String tableName, String colName, String where, Object... params) {
		String updateSQL = generator.generateUpdateStatementWhere(tableName, colName, where);
		
		return updateRecords(updateSQL, params);
	}
	
	/**
	 * 给定表名tableName、需要修改的列名数组colNames、ID值id及参数队列values修改对应记录。
	 * 参数队列的顺序必须与colNames中的所有'?'号一一对应。
	 */
	public int updateRecord(String tableName, Integer id, String[] colNames, Object... values) {
		String updateSQL = generator.generateUpdateStatementId(tableName, colNames);
		values = this.addParam(values, id);
		
		return updateRecords(updateSQL, values);
	}
	
	/**
	 * 给定表名tableName、需要修改的列名colName（只修改一列属性）、ID值id及修改列的对应值value。
	 */
	public int updateRecord(String tableName, Integer id, String colName, Object value) {
		String updateSQL = generator.generateUpdateStatementId(tableName, colName);
		
		return updateRecords(updateSQL, new Object[] {value, id});
	}
	
	/**
	 * 给定表名tableName、需要修改的列名数组colNames及参数队列values修改对应记录（没有查询条件，修改所有记录）。
	 * 参数队列的顺序必须与colNames中的所有'?'号一一对应。
	 */
	public int updateRecords(String tableName, String[] colNames, Object... values) {
		String updateSQL = generator.generateUpdateStatement(tableName, colNames);
		
		return updateRecords(updateSQL, values);
	}
	
	/**
	 * 给定表名tableName、需要修改的列名colName（只修改一列属性）及修改列的对应值value修改对应记录（没有查询条件，修改所有记录）。
	 */
	public int updateRecords(String tableName, String colName, Object value) {
		String updateSQL = generator.generateUpdateStatement(tableName, colName);
		
		return updateRecords(updateSQL, new Object[] {value});
	}
	
	/**
	 * 给定表名tableName、需要修改的列名数组colNames及对应的Bean，修改数据库中的相关记录（即与此Bean的ID相同的记录）。
	 */
	public int updateRecord(String tableName, String[] colNames_noid, Object bean) {
		String updateSQL = generator.generateUpdateStatementId(tableName, colNames_noid);
		String[] colNames = new String[colNames_noid.length + 1];
		for(int i = 0; i < colNames_noid.length; i++) {
			colNames[i] = colNames_noid[i];
		}
		colNames[colNames.length - 1] = IDFIELD;
		
		return updateBean(updateSQL, bean, colNames);
	}	

	// ==================================================================================
	// DELETE_OPERATIONS
	// ==================================================================================
	/**
	 * 给定一条delete删除语句deleteSQL及参数队列params删除对应记录。
	 * 参数队列中的顺序必须与delete中的所有'?'号一一对应。
	 */
	public int deleteRecords(String deleteSQL, Object... params) {
		Integer status = null;
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		try {
			status = queryRunner.update(connection, deleteSQL, params);
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return status;
	}
	
	/**
	 * 给定一条delete删除语句deleteSQL删除对应记录（没有参数，查询参数已包含在删除语句中）。
	 */
	public int deleteRecords(String deleteSQL) {
		return deleteRecords(deleteSQL, (Object[]) null);
	}
	
	/**
	 * 给定表名tableName、查询条件where（where参数中需要自带where关键字）及参数队列params删除对应记录。
	 * 参数队列的顺序必须与where条件的所有'?'号一一对应。
	 */
	public int deleteRecords(String tableName, String where, Object... params) {
		String deleteSQL = generator.generateDeleteStatementWhere(tableName, where);
		
		return deleteRecords(deleteSQL, params);
	}
	
	/**
	 * 给定表名tableName、ID值id删除对应记录。
	 */
	public int deleteRecord(String tableName, Integer id) {
		String deleteSQL = generator.generateDeleteStatementId(tableName);
		
		return deleteRecords(deleteSQL, id);
	}
	
	/**
	 * 给定表名tableName删除此表中的所有记录。
	 */
	public int deleteAllRecords(String tableName) {
		String deleteSQL = generator.generateDeleteStatement(tableName);
		
		return deleteRecords(deleteSQL);
	}
	
	// ==================================================================================
	// SELECT_OPERATIONS
	// ==================================================================================
	/**
	 * 给定一条select查询语句selectSQL、封装类resultClass及参数队列params查询对应记录。
	 * 参数队列的顺序必须与selectSQL中的所有'?'号一一对应。
	 * 如果没有匹配记录，则返回长度为0的空List。
	 */
	public <T> List<T> selectRecords(String selectSQL, Class<T> resultClass, Object... params) {
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		List<T> results = null;		
		try {
			results = (List<T>) queryRunner.query(connection, selectSQL,
					new BeanListHandler<T>(resultClass), params);
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return results;
	}
	
	/**
	 * 给定一条select查询语句selectSQL、封装类resultClass及参数队列params查询对应的单条记录。
	 * 参数队列的顺序必须与selectSQL中的所有'?'号一一对应。
	 * 如果没有匹配记录，则返回null。
	 */
	public <T> T selectRecord(String selectSQL, Class<T> resultClass, Object... params) {		
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		T result = null;		
		try {
			List<T> resultList = (List<T>) queryRunner.query(connection, selectSQL,
					new BeanListHandler<T>(resultClass), params);
			if(resultList == null || resultList.isEmpty()) return null;
			result = resultList.get(0);
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return result;
	}
	
	/**
	 * 给定一条select查询语句selectSQL及封装类resultClass查询对应记录。（没有参数，查询参数已包含在查询语句中）。
	 * 如果没有匹配记录，则返回长度为0的空List。
	 */
	public <T> List<T> selectRecords(String selectSQL, Class<T> resultClass) {
		return selectRecords(selectSQL, resultClass, (Object[]) null);
	}
	
	/**
	 * 给定一条select查询语句selectSQL及封装类resultClass查询对应的单条记录。（没有参数，查询参数已包含在查询语句中）。
	 * 如果没有匹配记录，则返回null。
	 */
	public <T> T selectRecord(String selectSQL, Class<T> resultClass) {
		return selectRecord(selectSQL, resultClass, (Object[]) null);
	}

	/**
	 * 给定表名tableName、查询列名数组colNames、
	 * 查询条件where（where参数中需要自带where关键字）封装类resultClass及参数队列params查询对应记录。
	 * 参数队列的顺序必须与where条件的所有'?'号一一对应。
	 * 如果没有匹配记录，则返回长度为0的空List。
	 */
	public <T> List<T> selectRecords(String tableName, String[] colNames, String where, Class<T> resultClass, Object... params) {
		String selectSQL = generator.generateSelectStatementWhere(tableName, colNames, where);
		
		return selectRecords(selectSQL, resultClass, params);
	}

	/**
	 * 给定表名tableName、查询列名数组colNames、
	 * 查询条件where（where参数中需要自带where关键字）封装类resultClass及参数队列params查询对应的单条记录。
	 * 参数队列的顺序必须与where条件的所有'?'号一一对应。
	 * 如果没有匹配记录，则返回null。
	 */
	public <T> T selectRecord(String tableName, String[] colNames, String where, Class<T> resultClass, Object... params) {
		String selectSQL = generator.generateSelectStatementWhere(tableName, colNames, where);
		
		return selectRecord(selectSQL, resultClass, params);
	}

	/**
	 * 给定表名tableName、查询列名数组colNames、
	 * ID值id及封装类resultClass查询对应记录。
	 * 如果没有匹配记录，则返回null。
	 */
	public <T> T selectRecord(String tableName, Integer id, String[] colNames, Class<T> resultClass) {
		String selectSQL = generator.generateSelectStatementId(tableName, colNames);
		List<T> resultList = selectRecords(selectSQL, resultClass, new Object[] {id});
		if(resultList == null || resultList.isEmpty()) return null;
		
		return resultList.get(0);
	}

	/**
	 * 给定一条select查询语句selectSQL及参数队列params查询对应记录，
	 * 将每条记录置入一个Map中，并将所有Map置入一个List中返回。
	 * 参数队列的顺序必须与selectSQL中的所有'?'号一一对应。
	 * （这个通常用在多表连接查询，而无法将结果封装为具体实例对象时使用）。
	 * 如果没有匹配记录，则返回长度为0的空List。
	 */
	public List<Map<String, Object>> selectRecords(String selectSQL, Object... params) {
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		List<Map<String, Object>> results = null;
		try {
			results = (List<Map<String, Object>>) queryRunner
					.query(connection, selectSQL, new MapListHandler(), params);
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			DBConnect.closeConnection(connection);
		}
		
		return results;
	}

	/**
	 * 给定一条select查询语句selectSQL查询对应记录（没有参数，查询参数已包含在查询语句中），
	 * 将每条记录置入一个Map中，并将所有Map置入一个List中返回。
	 * （这个通常用在多表连接查询，而无法将结果封装为具体实例对象时使用）。
	 * 如果没有匹配记录，则返回长度为0的空List。
	 */
	public List<Map<String, Object>> selectRecords(String selectSQL) {
		return selectRecords(selectSQL, (Object[]) null);
	}


	/**
	 * 获得查询结果的数量，where参数需包含where关键字
	 */
	public int getCount(String tableName, String where) {
		int count = 0;
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		String sql = generator.generateCountStatementId(tableName, IDFIELD, where);
		try {
			connection = DBConnect.getConnection();
			count = (Integer) queryRunner.query(connection, sql, new ScalarHandler(1));
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			try {
				connection.close();
			} catch (SQLException e) {
				debug.exception(e);
			}
		}
		
		return count;
	}
	
	// =======================================
	// 私有方法，将param参数并入参数数组中
	// =======================================
	private Object[] addParam(Object[] values, Object param) {
		Object temp[] = new Object[values.length + 1];
		System.arraycopy(values, 0, temp, 0, values.length);
		temp[temp.length - 1] = param;
		
		return temp;		
	}
	// =======================================
	// 私有方法，将根据给定的Bean更新对应记录
	// =======================================	
	private int updateBean(String updateSQL, Object bean, String[] colNames) {
		PreparedStatement stmt = null;
		Connection connection = null;
		QueryRunner queryRunner = new QueryRunner();
		int rows = 0;
		try {
			connection = DBConnect.getConnection();
			stmt = connection.prepareStatement(updateSQL);
			queryRunner.fillStatementWithBean(stmt, bean, colNames);
			rows = stmt.executeUpdate();
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			try {
				stmt.close();
				connection.close();
			} catch (SQLException e) {
				debug.exception(e);
			}
		}

		return rows;
	}
	// =======================================
	// 私有方法，将根据给定的Bean新增对应记录
	// =======================================	
	private Integer insertBean(String insertSQL, Object bean, String[] colNames) {
		Integer insertedId = null;
		PreparedStatement stmt = null;
		Connection connection = DBConnect.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		try {
			connection = DBConnect.getConnection();
			stmt = connection.prepareStatement(insertSQL);
			queryRunner.fillStatementWithBean(stmt, bean, colNames);
			stmt.executeUpdate();
			insertedId = (Integer) queryRunner.query(connection, generator.getInsertedIdMethod(),
					new ScalarHandler(1));
		} catch (SQLException e) {
			debug.exception(e);
		} finally {
			try {
				stmt.close();
				connection.close();
			} catch (SQLException e) {
				debug.exception(e);
			}
		}
		
		return insertedId;
	}

	
}
